{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python 正则表达式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "\n",
    "正则表达式是一个特殊的字符序列，它能帮助你方便的检查一个字符串是否与某种模式匹配。\n",
    "\n",
    "Python 自1.5版本起增加了re 模块，它提供 Perl 风格的正则表达式模式。\n",
    "\n",
    "re 模块使 Python 语言拥有全部的正则表达式功能。\n",
    "\n",
    "compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。\n",
    "\n",
    "re 模块也提供了与这些方法功能完全一致的函数，这些函数使用一个模式字符串做为它们的第一个参数。\n",
    "\n",
    "本章节主要介绍Python中常用的正则表达式处理函数。\n",
    "\n",
    "'''\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "\n",
    "re.match函数\n",
    "re.match 尝试从字符串的起始位置匹配一个模式，如果不是起始位置匹配成功的话，match()就返回none。\n",
    "\n",
    "函数语法：\n",
    "\n",
    "re.match(pattern, string, flags=0)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "函数参数说明：\n",
    "\n",
    "参数\t描述\n",
    "pattern\t匹配的正则表达式\n",
    "string\t要匹配的字符串。\n",
    "flags\t标志位，用于控制正则表达式的匹配方式，如：是否区分大小写，多行匹配等等。参见：正则表达式修饰符 - 可选标志\n",
    "匹配成功re.match方法返回一个匹配的对象，否则返回None。\n",
    "\n",
    "我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。\n",
    "\n",
    "匹配对象方法\t描述\n",
    "group(num=0)\t匹配的整个表达式的字符串，group() 可以一次输入多个组号，在这种情况下它将返回一个包含那些组所对应值的元组。\n",
    "groups()\t返回一个包含所有小组字符串的元组，从 1 到 所含的小组号。\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 3)\n",
      "None\n",
      "(0, 6)\n",
      "matchObj.group() :  Cats are smarter than dogs\n",
      "matchObj.group(0) :  Cats are smarter than dogs\n",
      "matchObj.group(1) :  Cats\n",
      "matchObj.group(2) :  smarter\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "print(re.match('www', 'www.runoob.com').span())  # 在起始位置匹配\n",
    "print(re.match('com', 'www.runoob.com'))         # 不在起始位置匹配\n",
    "print(re.match('123456','1234567890').span())\n",
    "\n",
    "\n",
    "line = \"Cats are smarter than dogs\"\n",
    "\n",
    "matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)\n",
    " \n",
    "if matchObj:\n",
    "    print(\"matchObj.group() : \", matchObj.group())\n",
    "    print(\"matchObj.group(0) : \", matchObj.group(0))\n",
    "    print(\"matchObj.group(1) : \", matchObj.group(1))\n",
    "    print(\"matchObj.group(2) : \", matchObj.group(2))\n",
    "else:\n",
    "    print(\"No match!!\")\n",
    "    \n",
    "    \n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "searchObj.group() :  Cats are smarter than dogs\n",
      "searchObj.group(0) :  Cats are smarter than dogs\n",
      "searchObj.group(1) :  Cats\n",
      "searchObj.group(2) :  smarter\n"
     ]
    }
   ],
   "source": [
    "\n",
    "searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)\n",
    "\n",
    "if matchObj:\n",
    "    print(\"searchObj.group() : \", searchObj.group())\n",
    "    print(\"searchObj.group(0) : \", searchObj.group(0))\n",
    "    print(\"searchObj.group(1) : \", searchObj.group(1))\n",
    "    print(\"searchObj.group(2) : \", searchObj.group(2))\n",
    "else:\n",
    "    print(\"No match!!\")\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 3)\n",
      "(11, 14)\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    " \n",
    "print(re.search('www', 'www.runoob.com').span())  # 在起始位置匹配\n",
    "print(re.search('com', 'www.runoob.com').span())         # 不在起始位置匹配"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n\\nre.match与re.search的区别\\nre.match只匹配字符串的开始，如果字符串开始不符合正则表达式，则匹配失败，函数返回None；而re.search匹配整个字符串，直到找到一个匹配。\\n\\n'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''\n",
    "\n",
    "re.match与re.search的区别\n",
    "re.match只匹配字符串的开始，如果字符串开始不符合正则表达式，则匹配失败，函数返回None；而re.search匹配整个字符串，直到找到一个匹配。\n",
    "\n",
    "'''\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 检索和替换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "\n",
    "Python 的re模块提供了re.sub用于替换字符串中的匹配项。\n",
    "\n",
    "语法：\n",
    "\n",
    "re.sub(pattern, repl, string, count=0, flags=0)\n",
    "参数：\n",
    "\n",
    "pattern : 正则中的模式字符串。\n",
    "repl : 替换的字符串，也可为一个函数。\n",
    "string : 要被查找替换的原始字符串。\n",
    "count : 模式匹配后替换的最大次数，默认 0 表示替换所有的匹配。\n",
    "flags : 编译时用的匹配模式，数字形式。\n",
    "前三个为必选参数，后两个为可选参数。\n",
    "\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num =  2004-959-559 \n",
      " num =  2004959559\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "phone = \"2004-959-559 # 这是一个电话号码\"\n",
    "# 删除注释\n",
    "num = re.sub(r'#.*$',\"\",phone)\n",
    "print('num = ',num)\n",
    "\n",
    "# 移除非数字的内容\n",
    "num = re.sub(r'\\D',\"\",phone)\n",
    "print(\" num = \",num)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A46G8HFD1134\n",
      "A46G8HFD101214\n"
     ]
    }
   ],
   "source": [
    "#  repl 参数是一个函数\n",
    "\n",
    "def double(matched):\n",
    "    value = int(matched.group('value'))\n",
    "    return str(value * 2)\n",
    "\n",
    "s = 'A23G4HFD567'\n",
    "print(re.sub('(?P<value>\\d+)', double, s))\n",
    "print(re.sub('(?P<value>\\d)', double, s))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# compile 函数\n",
    "\n",
    "\n",
    "'''\n",
    "\n",
    "compile 函数用于编译正则表达式，生成一个正则表达式（ Pattern ）对象，供 match() 和 search() 这两个函数使用。\n",
    "\n",
    "语法格式为：\n",
    "\n",
    "re.compile(pattern[, flags])\n",
    "参数：\n",
    "\n",
    "pattern : 一个字符串形式的正则表达式\n",
    "flags 可选，表示匹配模式，比如忽略大小写，多行模式等，具体参数为：\n",
    "re.I 忽略大小写\n",
    "re.L 表示特殊字符集 \\w, \\W, \\b, \\B, \\s, \\S 依赖于当前环境\n",
    "re.M 多行模式\n",
    "re.S 即为' . '并且包括换行符在内的任意字符（' . '不包括换行符）\n",
    "re.U 表示特殊字符集 \\w, \\W, \\b, \\B, \\d, \\D, \\s, \\S 依赖于 Unicode 字符属性数据库\n",
    "re.X 为了增加可读性，忽略空格和' # '后面的注释\n",
    "\n",
    "'''\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m =  None\n",
      "m =  None\n",
      "m =  <re.Match object; span=(3, 6), match='129'>\n",
      "m.span(0) :  (3, 6)\n",
      "m.group(0) :  129\n",
      "m.start(0) :  3\n",
      "m.end(0) :  6\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "str = 'one129agarhe'\n",
    "pattern = re.compile(r'\\d+')# 用于匹配至少一个数字 \n",
    "m = pattern.match(str)# 查找头部，没有匹配\n",
    "print('m = ',m)\n",
    "\n",
    "m = pattern.match(str,2,10) # 从'e'的位置开始匹配，没有匹配\n",
    "print('m = ',m)\n",
    "\n",
    "m = pattern.match(str,3,10)# 从'1'的位置开始匹配，正好匹配 \n",
    "print('m = ',m)            # 返回一个 Match 对象\n",
    "\n",
    "print('m.span(0) : ',m.span(0)) \n",
    "print('m.group(0) : ',m.group(0)) \n",
    "print('m.start(0) : ',m.start(0)) \n",
    "print('m.end(0) : ',m.end(0)) \n",
    "\n",
    "\n",
    "'''\n",
    "\n",
    "在上面，当匹配成功时返回一个 Match 对象，其中：\n",
    "\n",
    "group([group1, …]) 方法用于获得一个或多个分组匹配的字符串，当要获得整个匹配的子串时，可直接使用 group() 或 group(0)；\n",
    "start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置（子串第一个字符的索引），参数默认值为 0；\n",
    "end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置（子串最后一个字符的索引+1），参数默认值为 0；\n",
    "span([group]) 方法返回 (start(group), end(group))。\n",
    "\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m =  <re.Match object; span=(0, 11), match='Hello World'>\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)\n",
    "m = pattern.match('Hello World Wide Web')\n",
    "print('m = ', m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " result1  =  ['13', '875']\n",
      " reuslt2  =  ['1']\n"
     ]
    }
   ],
   "source": [
    "# findall 函数\n",
    "\n",
    "'''\n",
    "\n",
    "在字符串中找到正则表达式所匹配的所有子串，并返回一个列表，如果没有找到匹配的，则返回空列表。\n",
    "\n",
    "注意： match 和 search 是匹配一次 findall 匹配所有。\n",
    "\n",
    "语法格式为：\n",
    "\n",
    "re.findall(string[, pos[, endpos]])\n",
    "参数：\n",
    "\n",
    "string 待匹配的字符串。\n",
    "pos 可选参数，指定字符串的起始位置，默认为 0。\n",
    "endpos 可选参数，指定字符串的结束位置，默认为字符串的长度。\n",
    "查找字符串中的所有数字：\n",
    "\n",
    "'''\n",
    "\n",
    "\n",
    "\n",
    "import re\n",
    "pattern = re.compile(r'\\d+')   # 查找数字\n",
    "str = 'adfa 13 and 875'\n",
    "result1 = pattern.findall(str)\n",
    "reuslt2 = pattern.findall(str,0,6)\n",
    "print(' result1  = ',result1)\n",
    "print(' reuslt2  = ',reuslt2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "12\n",
      "32\n",
      "43\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "\n",
    "re.finditer\n",
    "和 findall 类似，在字符串中找到正则表达式所匹配的所有子串，并把它们作为一个迭代器返回。\n",
    "\n",
    "re.finditer(pattern, string, flags=0)\n",
    "\n",
    "'''\n",
    "\n",
    "\n",
    "it = re.finditer(r\"\\d+\",\"12a32bc43jf3\") \n",
    "for match in it:\n",
    "    print(match.group())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['android', 'java', 'keep', 'python']\n",
      "['', '———— ', ' ', '']\n",
      "['', 'h', 'e', '', 'o', ' ', 'w', 'o', 'r', '', 'd', '']\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "\n",
    "\n",
    "re.split\n",
    "split 方法按照能够匹配的子串将字符串分割后返回列表，它的使用形式如下：\n",
    "\n",
    "re.split(pattern, string[, maxsplit=0, flags=0])\n",
    "参数：\n",
    "\n",
    "参数\t描述\n",
    "pattern\t匹配的正则表达式\n",
    "string\t要匹配的字符串。\n",
    "maxsplit\t分隔次数，maxsplit=1 分隔一次，默认为 0，不限制次数。\n",
    "flags\t标志位，用于控制正则表达式的匹配方式，如：是否区分大小写，多行匹配等等。参见：正则表达式修饰符 - 可选标志\n",
    "\n",
    "'''\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "import re\n",
    "\n",
    "print(re.split(r'\\W+','android java keep python'))\n",
    "print(re.split(r'\\w+','123———— keep python'))\n",
    "\n",
    "\n",
    "print(re.split('l*', 'hello world'))   # 对于一个找不到匹配的字符串而言，split 不会对其作出分割"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
